package com 
{
	import data.*;
	
	import events.GCEvent;
	import events.GCQuestEvent;
	
	import flash.display.DisplayObject;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	/**
	 * A class that keeps track of the players progress within the tutorial.
	 * 
	 */
	public class GCTutorial extends EventDispatcher
	{
		/*
		 * The different tutorial stages that a player can be in right now. If the player is at a
		 * particular stage, it means that they have completed all previous tasks defined in prior
		 * stages.
		 * 
		 * In order for menus to know when to trigger that a subgoal has been completed it will need
		 * to know not only the current tutorial stage, but also an id of what goals are currently in progress.
		 * Depending on which ones have not been completed, certain actions may still be locked at that
		 * stage.
		 */
		
		// The very start of the game, at world map
		public static const STAGE_VERY_START:uint = 0;
		
		// Player is selling items for the first time
		/*
		 * Subgoals:
		 * 1.) Sell enough items to make 200 gold
		 * 2.) View inventory for items
		 */
		public static const STAGE_START_CITY:uint = 1;
		
		// Player fulfilling first order and buying first items from market.
		/*
		 * Subgoals:
		 * 1.) Buy the correct amount from the market
		 * 2.) Fulfill the first order
		 * 3.) As side effect, gain first level
		 * 
		 * At end:
		 * - Level up and get ship
		 * - Gain access to view world map
		 */
		public static const STAGE_FIRST_ORDER:uint = 2;
		
		// Player has a ship, must make first journey to predefined city, buy the appropriate amount of food
		// for journey, load and unload goods. Get a new order at another city (Tafferel)
		/*
		 * Subgoals:
		 * 1.) Buy enough food to make the journey. (Let them know from now on all bought goods go on ship)
		 * 2.) Buy enough goods to fulfill the buy order and load it onto the ship.
		 * (This will be detected when they load the appropriate amount in the warehouse menu or buy the
		 * correct amount from the market.)
		 * 3.) Travel to another city. (Can only head travel to other city only after the specifed amount has been
		 * loaded onto the ship.)
		 * 
		 * At end:
		 * -- Player goes to another city.
		 */
		public static const STAGE_FIRST_JOURNEY:uint = 3;
		
		// Player at new city, must fulfill the order at this city
		/*
		 * Subgoals:
		 * 1.) Can only view the market
		 * 2.) Buy enough of some other good
		 * 3.) Fulfill the order that was requested
		 * 4.) Return to old city (Cannot continue until all finished)
		 * 
		 * At end:
		 * -- Players finished with tasks at this city
		 * -- Level up again, rewarded with a batch of goods and gold
		 */
		public static const STAGE_AT_NEW_CITY:uint = 4;
		
		/*
		 * Subgoals:
		 * 1.) Sell the goods purchased from other cities (auto buy goods)
		 * 2.) Fulfill a number of very easy orders (some may require sailing back and forth)
		 * 3.) Perform enough to levelup (level 4?)
		 * 
		 * At end:
		 * -- Players finished with tasks at this city
		 * -- At a high enough level to gain access to workers
		 */
		public static const STAGE_ON_RETURN:uint = 5;
		
		// Player is back at old city. Introduce player to gathering their own resources.
		// Start off by asking them to build farm and assign a few workers
		/*
		 * Subgoals:
		 * 1.) Build a farm (only available )
		 * 2.) Assign all workers to the farm
		 * 
		 * --use the resources gathered from farm to pay for travel costs or sell
		 * excess food
		 */
		public static const STAGE_BUILD_GATHER:uint = 6;
		
		
		// Player is introduced to the concept of establishing trade posts at other cities.
		/*
		 * Subgoals:
		 * 1.) Sail to a different city
		 * 2.) Build a warehouse at that city.
		 * 3.) Sell a specified number of and type of good
		 * 
		 * -- at this point random npc orders should start appearing
		 */
		public static const STAGE_ESTABLISH_NEW_CENTER:uint = 7;
		
		// Player is introduced to recipes
		// (unlock synthesis menu option here)
		/*
		 * Subgoals:
		 * 1.)
		 * 2.)
		 */
		public static const STAGE_TUTORIAL_COMPLETE:uint = 8;
		
		public static const SELL_TOO_LOW:String = "That price is a bit too low";
		public static const SELL_TOO_HIGH:String = "That price is a bit too high";
		
		/*
		 * Keeps track of the progress the player has made in the tutorial, essentially just acts
		 * as a counter of how many tutorial goals the player has finished. The counter gets incremented
		 * each time the player does something to make progress in the tutorial.
		 */
		private var _currentTutorialStage:uint;
		
		// An instance of this tutorial object
		private static var _instance:GCTutorial;
		
		// A list of sub goals that the player is currrently trying to
		// complete in order to advance to the next stage of the tutorial.
		// A bit hacky
		// key: template id
		// value: GCQuest
		private static var _subGoals:Dictionary;
		
		// Keep track of the number of remaining sub-goals before the stage can be complete
		private static var _remainingSubGoals:uint;
		
		/*
		 * Some tutorial messages
		 */
		public static const GAME_WELCOME_MESSAGE:String = "Welcome merchant to the world of \nFree Traders. \n\nHover over the city of Picaroon and enter it to begin your journey!";
		 
		public static const CITY_INTRODUCTION_MESSAGE:String = "Welcome to Picaroon.\n, Here you have a warehouse here with a few goods and a market	." +
						"\n\nYour warehouse stores goods that you can put on sale at this city. \n\nThe market is where you buy and sell with other players. " +
						"You also have a new task!";
		
		public static const EXPANSION_MESSAGE:String = "You are well on your way to creating an awesome trade empire. Now you need to upgrade your ship and expand your " +
										"operations to new cities!" +
										"\n\nYou have been rewarded a recipe for a new ship upgrade to help in this task, it can be found in your ship inventory!";
						
		public function GCTutorial(stage:uint) 
		{
			_currentTutorialStage = stage;
		}
		
		/**
		 * Get the current stage the player is at in the
		 * tutorial.
		 */
		public function get currentTutorialStage():uint
		{
			return _currentTutorialStage;
		}
		
		/**
		 * Go to the next stage of the tutorial. This will load up
		 * a fresh set of tutorial quests that need to be accomplished.
		 */
		public function goToNextStage():void
		{
			_currentTutorialStage++;
			trace("GCTutorial " + _currentTutorialStage);
			
			// Set up a new batch of subgoals
			_subGoals = this.getNextTutorialQuests(_currentTutorialStage);
		}
		
		/**
		 * Get an instance of the tutorial object.
		 * 
		 * @param	stage
		 * @return
		 */
		public static function getInstance(stage:uint, goalsInProgress:Dictionary = null):GCTutorial
		{
			if (_instance == null)
			{
				_instance = new GCTutorial(stage);
				_subGoals = new Dictionary();
				_remainingSubGoals = 0;
				
				// Must correctly set up parameters for goals in progress
				if (goalsInProgress != null)
				{
					var numTutorialGoals:uint = 0;
					for (var obj:Object in goalsInProgress)
					{
						var template:uint = obj as uint;
						trace("GCTutorial adding a tutorial from the DB>>>>>>>>>>>>>>>>>>>>>>>>");
						var tutorialQuest:GCQuest = goalsInProgress[template];
						numTutorialGoals++;
						
						tutorialQuest.setQuestParameter(GCQuest.XP, GCQuestData.getTutorialExperienceFromId(template));
						tutorialQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuestData.getTutorialVisibilityFromId(template));
						
						_remainingSubGoals++;
						_subGoals[template] = tutorialQuest;
						
						if (stage == STAGE_FIRST_JOURNEY && template == GCQuestData.QUEST_TEMPLATE_TUTORIAL_6)
						{
							_remainingSubGoals--;
						}
					}
					
					// Player ended up in a corrupted state regarding tutorials, help them recover in here
					if (numTutorialGoals == 0)
					{
						trace("---------------------CORRUPTED STATE------------------------");
						_instance.getNextTutorialQuests(stage);
						
						for each(var corruptedQuest:GCQuest in _subGoals)
						{
							GCPlayState.playerData.addQuest(corruptedQuest);
						}
						
						if (stage == STAGE_AT_NEW_CITY)
						{
							var newQuest:GCQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_6, 1, GCCityData.CITY_TAFFEREL,
								0, GCItemData.ITEM_IRON, 5, 0, 150);
							newQuest.setQuestParameter(GCQuest.XP, 20);
							_subGoals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_6] = newQuest;
							GCPlayState.playerData.addQuest(newQuest);
						}
					}
				}
				/*if (stage == STAGE_AT_NEW_CITY)
				{
					var newQuest:GCQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_6, 1, GCCityData.CITY_TAFFEREL,
						0, GCItemData.ITEM_IRON, 5, 0, 150);
					newQuest.setQuestParameter(GCQuest.XP, 20);
					_subGoals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_6] = newQuest;
				}*/
			}
			return _instance;
		}
		
		/**
		 * Gets the list of subgoals currently the player needs to complete
		 */
		public function get tutorialSubGoals():Dictionary
		{
			return _subGoals;
		}
		
		/**
		 * Get the number of remaining subgoals for this stage.
		 */
		public function get numRemainingSubGoals():uint
		{
			return _remainingSubGoals;
		}
		
		public function set tutorialSubGoals(goals:Dictionary):void
		{
			_subGoals = goals;	
		}
		
		/**
		 * This function should be called when a subgoal has been completed and should
		 * be deleted from the list.
		 * 
		 * @param	id
		 * 			The unique template id for the goal.
		 */
		public function removeSubgoal(id:uint):void
		{
			if (_remainingSubGoals > 0)
			{
				_remainingSubGoals -= 1;
				_subGoals[id] = null;
				delete _subGoals[id];
			}
			else
			{
				trace("GCTutorial-- ERROR incorrectly removing a subgoal from stage " + _currentTutorialStage);
			}
		}
		
		/**
		 * Get the tutorial quest object from the given template id.
		 * Returns null if that tutorial quest is not active
		 * (i.e. it has already been completed)
		 * 
		 * @param	id
		 * 			The template id.
		 * @return
		 */
		public function getTutorialQuestFromTemplate(id:uint):GCQuest
		{
			(_subGoals[id] == null) ? trace("GCTutorial-- Subgoal does not exist " + id) : trace("GCTutorial-- Subgoal found " + id);
			return _subGoals[id];
		}
		
		/**
		 * Have a predefined list of tutorial quests that the player must complete in
		 * order to unlock all the features of the game. (NPC orders in this tutorial sequence must
		 * be handled a bit differently, reuse the same architecture but hardcode a few of the
		 * templates and trigger specific end of quest messages)
		 * 
		 * We have a list of quests, we must use the currentStage counter plus a list
		 * of in progress quests (using their template ids, to determine which quest we
		 * should get next)
		 * templateId:uint, assignerId:uint, lid:uint, time:uint, requestedGoalId:uint, requestedGoalAmount:uint, rewardId:uint, rewardAmount:uint
		 */
		public function getNextTutorialQuests(stage:uint):Dictionary
		{
			var goals:Dictionary = _subGoals;//new Dictionary();
			var newQuest:GCQuest;
			switch(stage)
			{
				case STAGE_START_CITY:
					_remainingSubGoals = 1;
					
					// Ask player to post enough sales to make at least 200 gold
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_0, 0, GCCityData.CITY_PICAROON,
														0, 0, 200, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 45);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_0] = newQuest;
					break;
				case STAGE_FIRST_ORDER:
					_remainingSubGoals = 2;
					
					// Ask player to buy at least 10 lumber (Hidden)
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_1, 0, GCCityData.CITY_PICAROON,
														0, GCItemData.ITEM_LUMBER, 10, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 45);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_1] = newQuest;
					
					// NPC order at Picaroon for 10 lumber
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_2, 1, GCCityData.CITY_PICAROON,
														0, GCItemData.ITEM_LUMBER, 10, 0, 400);
					newQuest.setQuestParameter(GCQuest.XP, 11);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_2] = newQuest;
					break;
				case STAGE_FIRST_JOURNEY:
					_remainingSubGoals = 3; 	// want to display the order here, but can't fulfill until next stage
					
					// Ask player to buy at least 10 food
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_3, 0, GCCityData.CITY_PICAROON,
														0, GCItemData.ITEM_FOOD, 5, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 50);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_3] = newQuest;
					
					// Ask player to buy at least 5 iron
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_4, 1, GCCityData.CITY_PICAROON,
														0, GCItemData.ITEM_IRON, 5, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 40);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_4] = newQuest;
					
					// Ask player to sail to Tafferel
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_5, 1, GCCityData.CITY_TAFFEREL,
														0, 0, 0, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 20);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_5] = newQuest;
					
					// Ask player to fulfill order at Tafferel
					// A bit hacky that it gets added to this stage
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_6, 1, GCCityData.CITY_TAFFEREL,
						0, GCItemData.ITEM_IRON, 5, 0, 200);
					newQuest.setQuestParameter(GCQuest.XP, 20);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_6] = newQuest;
					
					break;
				case STAGE_AT_NEW_CITY:
					_remainingSubGoals = 3;
					
					// Ask player to buy items from market in Tafferel
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_7, 1, GCCityData.CITY_TAFFEREL,
														0, GCItemData.ITEM_COTTON, 15, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 50);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_7] = newQuest;
					
					// Ask player to return to Picaroon
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_8, 1, GCCityData.CITY_PICAROON,
						0, 0, 0, 0, 0);
					//newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 0);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_8] = newQuest;
					break;
				case STAGE_ON_RETURN:
					_remainingSubGoals = 4;
					
					// First timed order
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_9, 1, GCCityData.CITY_PICAROON,
						10, GCItemData.ITEM_FOOD, 10, 0, 150);
					newQuest.setQuestParameter(GCQuest.XP, 30);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_9] = newQuest;
					
					// Ask player to sell goods purchased from Tafferel
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_10, 1, GCCityData.CITY_PICAROON,
						0, GCItemData.ITEM_COTTON, 15, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 80);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_10] = newQuest;
					
					// Must level up to move to the next stage
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_11, 1, GCCityData.CITY_PICAROON,
						0, 0, 4, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 0);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_11] = newQuest;
					
					// A hidden goal player must load and unload from ship for the first time
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_18, 1, GCCityData.CITY_PICAROON,
						0, 0, 0, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 0);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_18] = newQuest;
					
					break;
				case STAGE_BUILD_GATHER:
					_remainingSubGoals = 3;
				
					// Ask player to build their first farm by going to build menu
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_12, 1, GCCityData.CITY_PICAROON,
						0, GCBuildingData.BUILDING_FARM, 1, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 70);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_12] = newQuest;
					
					// Ask player to assign worker
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_13, 1, GCCityData.CITY_PICAROON,
						0, GCBuildingData.BUILDING_FARM, 3, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 50);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_13] = newQuest;
					
					// Tell them to gather a set amount of food from farms
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_17, 1, GCCityData.CITY_PICAROON,
						0, GCItemData.ITEM_FOOD, 3, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 50);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_17] = newQuest;
					break;
				case STAGE_ESTABLISH_NEW_CENTER:
					_remainingSubGoals = 3;

					// Ask player to build a new warehouse in Tafferel
					// Ask player to build their first farm by going to build menu
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_14, 1, GCCityData.CITY_TAFFEREL,
						0, GCBuildingData.BUILDING_WAREHOUSE, 0, 0, 0);
					newQuest.setQuestParameter(GCQuest.XP, 100);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_14] = newQuest;
					
					// Reward player with a recipe, tell them to synthesize it
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_15, 1, GCCityData.CITY_TAFFEREL,
						0, 0, 0, 0, 0);
					newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 150);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_15] = newQuest;
					
					// Tell them to apply the upgrade on the ship
					newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_16, 1, GCCityData.CITY_TAFFEREL,
						0, 0, 0, 0, 0);
					//newQuest.setQuestParameter(GCQuest.DISPLAYABLE, GCQuest.FALSE);
					newQuest.setQuestParameter(GCQuest.XP, 150);
					goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_16] = newQuest;
					
					// Big goal, travel to a previously locked city
					//newQuest = new GCQuest(GCQuestData.QUEST_TEMPLATE_TUTORIAL_19, 1, GCCityData.CITY_TAFFEREL,
					//	0, 0, 0, 0, 0);
					//newQuest.setQuestParameter(GCQuest.XP, 50);
					//goals[GCQuestData.QUEST_TEMPLATE_TUTORIAL_19] = newQuest;
					break;
			}
			return goals;
		}
	}

}